package util

import (
	"errors"
	"fmt"
	"time"

	"gitee.com/daonna/collab-manage-system/pkg/consts"

	"github.com/golang-jwt/jwt/v4"
)

// jwtSecret 签名秘钥
var jwtSecret = []byte("yijiansanlian")

// Claims 结构体， 表示 JWT 载荷  (用户认证)
type Claims struct {
	ID        uint   `json:"id"`
	UserName  string `json:"user_name"`
	Authority int    `json:"authority"`
	jwt.StandardClaims
}

// GenerateToken 生成用户 JWT 令牌 ,传入 id userName authority 载荷，返回 token，如果错误返回err
func GenerateToken(id uint, userName string, authority int) (string, error) {
	// 获取当前时间，并设置过期时间为24小时后
	nowTime := time.Now()
	expireTime := nowTime.Add(24 * time.Hour)
	// 创建 JWT 载荷
	claims := Claims{
		ID:        id,
		UserName:  userName,
		Authority: authority,
		StandardClaims: jwt.StandardClaims{
			ExpiresAt: expireTime.Unix(),
			Issuer:    "FanOne-sbl",
		},
	}
	// 创建 JWT 令牌 ，使用 HS256 算法，hash 加密
	tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	// 使用签名秘钥对令牌进行签名
	token, err := tokenClaims.SignedString(jwtSecret)
	return token, err
}

// ParseToken 验证用户token ，传入 token 返回 Claims 和 error
func ParseToken(token string) (*Claims, error) {
	tokenCliams, err := jwt.ParseWithClaims(token, &Claims{}, func(t *jwt.Token) (interface{}, error) {
		return jwtSecret, nil
	})
	if tokenCliams != nil {
		// 检查 token 是否有效
		if claims, ok := tokenCliams.Claims.(*Claims); ok && tokenCliams.Valid {
			return claims, nil
		}
	}
	return nil, err
}

// ParseRefreshToken 验证并刷新用户token
func ParseRefreshToken(accessToken, refreshToken string) (newAccessToken, newRefreshToken string, err error) {
	// 首先尝试解析 access token
	accessClaims, err := ParseToken(accessToken)
	if err != nil {
		// 如果 access token 无效，检查是否是过期错误
		if !errors.Is(err, jwt.ErrTokenExpired) {
			return "", "", fmt.Errorf("access token 无效: %w", err)
		}
	}

	// 解析 refresh token
	refreshClaims, err := ParseToken(refreshToken)
	if err != nil {
		return "", "", fmt.Errorf("refresh token 无效: %w", err)
	}

	// 检查 refresh token 是否过期
	if time.Now().Unix() > refreshClaims.ExpiresAt {
		return "", "", errors.New("refresh token 已过期，请重新登录")
	}

	// 如果 access token 还没过期，直接返回原 tokens
	if accessClaims != nil && time.Now().Unix() < accessClaims.ExpiresAt {
		return accessToken, refreshToken, nil
	}

	// 生成新的 access token
	newAccessToken, err = GenerateToken(
		refreshClaims.ID,
		refreshClaims.UserName,
		refreshClaims.Authority,
	)
	if err != nil {
		return "", "", fmt.Errorf("生成新 access token 失败: %w", err)
	}

	// 如果 refresh token 快过期（比如剩余时间小于7天），也生成新的
	if time.Now().Unix() > refreshClaims.ExpiresAt-7*24*3600 {
		newRefreshToken, err = GenerateRefreshToken(refreshClaims.ID)
		if err != nil {
			return "", "", fmt.Errorf("生成新 refresh token 失败: %w", err)
		}
	} else {
		newRefreshToken = refreshToken
	}

	return newAccessToken, newRefreshToken, nil
}

// GenerateRefreshToken 生成刷新令牌
func GenerateRefreshToken(id uint) (string, error) {
	nowTime := time.Now()
	expireTime := nowTime.Add(consts.RefreshTokenExpireDuration)

	claims := Claims{
		ID: id,
		StandardClaims: jwt.StandardClaims{
			ExpiresAt: expireTime.Unix(),
			Issuer:    "FanOne-sbl",
		},
	}

	tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	return tokenClaims.SignedString(jwtSecret)
}
